Two
VBScript programs to output all users in the domain with the date and time each last logged onto
the domain. These program can be useful to identify old unused accounts that can be disabled and
eventually deleted. Also a program to document the last logon dates for all
users specified in a text file.
Because the lastLogon attribute is not replicated in Active Directory, a different value can be
stored in the copy of Active Directory on each Domain Controller. The programs first use ADO to
search Active Directory for all Domain Controllers. The ADsPath of each is saved in an array.
Next, ADO is used to search the copy of Active Directory on each Domain Controller for all users
and retrieve the lastLogon attribute. The latest date found for each user is saved in a dictionary
object. Once all Domain Controllers have been queried, the program outputs each
user's Distinguished Name and the latest lastLogon date. The values for each user are
output on a separate line delimited by a semicolon. If the output is redirected to a text file,
it can be easily read by a spreadsheet program like Microsoft Excel.
The lastLogon attribute is stored in Active Directory as Integer8 (8 bytes). This means it is a
64-bit number, which cannot be handled directly by VBScript. Instead, the LDAP IADsLargeInteger
interface provides HighPart and LowPart methods that break the number into two 32-bit components.
The resulting value represents the number of 100 nanosecond intervals since 12:00 AM January 1,
1601. The date represented by this number is in Coordinated Universal Time (UTC). It must be
adjusted by the time zone bias in the local machine registry to convert to local time.
The techniques in this program can be used to handle any attribute that is not replicated. Also,
the conversion formulas used apply to all Integer8 attributes that represent dates, such as
"pwdLastSet", "accountExpires", "badPasswordTime", and
"lockoutTime".
The program should be run at a command prompt with the cscript host. The output can be redirected
to a text file. For example, you can run the program with the following command:
cscript //nologo LastLogon.vbs > output.txt
LastLogon.txt <<-- Click here to view or download the program
If your domain is at Windows Server 2003 functional level or higher, there is a new attribute called
lastLogonTimeStamp you can use. Like lastLogon, this attribute is Integer8 and represents the
time when the user last logged onto the domain. Unlike lastLogon, this new attribute is
replicated. However, it is only updated when the user logs on if the old value is more than
14 days in the past. That means the value can only be trusted if it is more than 14 days in
the past, which is fine for finding old unused accounts. This behavior reduces the synchronization
load while still giving administrators the information they need.
Actually, the 14 day value can be modified by assigning a new value to the new
msDS-LogonTimeSyncInterval attribute (in days). When a user logs on, if the current value
of lastLogonTimeStamp is older than the current time less msDS-LogonTimeSyncInterval, then
the value of lastLogonTimeStamp is updated (and this updated value replicates).
When the domain is first raised to Windows Server 2003 functional level or higher, the value of
lastLogonTimeStamp is initially updated after 14 days minus a random percentage of 5 days.
This spreads out the initial replication of lastLogonTimeStamp for all users over a 5 day period.
A VBScript program to retrieve the value of lastLogonTimeStamp for all users only needs to query
one Domain Controller. The example program is linked below:
LastLogonTimeStamp.txt <<-- Click here to view or download the program
Finally,
a program similar to the first one linked above is provided, but instead of documenting
all users in the domain, this program only documents the users listed in a
text file. The name and path of the file are hardcoded in the program. The
file should have one user name per line. The names should be the
"pre-Windows 2000 logon names" of the users (the value of the sAMAccountName
attribute).
LimitedLastLogon.txt <<-- Click here to view or download the program
A PowerShell
script has also been developed to query all Domain Controllers in the domain
for the largest (latest) value of the lastLogon attribute for each user in
the domain. This program uses the DirectoryServices.DirectorySearcher
object. The last logon dates for each user are converted into local time.
The times are adjusted for daylight savings time, so they may differ from
the values reported by the LastLogon.vbs program by one hour. This program
works in PowerShell V1 and V2.
PSLastLogon.txt <<-- Click here to view or download the program
A similar program follows using the Get-ADDomainController and Get-ADUser
cmdlets in PowerShell V2. This program will only work if all Domain Controllers have the Active
Directory Web Services (ADWS) running. This requires Windows Server 2008 R2 or higher on all
Domain Controllers in the domain. This program is also considerably slower.
PSLastLogon2.txt <<-- Click here to view or download the program
Finally, a PowerShell script is linked below
that is very similar to the program LimitedLastLogon.vbs linked above,
except it retrieves the lastLogonTimeStamp attribute for all users specified
in a text file. Again, the "pre-Windows 2000 logon" names are read from the
text file. Because the program retrieves lastLogonTimeStamp, only one query
is required. This program works in PowerShell V1 and V2. If you modify this
program to retrieve the lastLogon attribute instead, you will need to add
the code to enumerate all Domain Controllers, repeat the query on each, and
track the largest values for each user in a hash table. This code can be
copied from PSLastLogon.ps1 linked above.
PSLimitedLastLogon.txt <<-- Click here to view or download the program